package Config::System::t::Property;

use strict;
use warnings;
use Test::More;
use Test::Exception;
use aliased 'Config::System::Property';

use base 'Test::Class';

sub make_verbose_eut: Test(setup) {
    shift->{eut} = Property->new
        (name => 'Verbose', isa => 'Bool', section => 'Qux');
}

sub eut { shift->{eut} }

sub simple: Test {
    my $self = shift;
    $self->eut->set(1);
    is $self->eut->get, 1;
}

sub fail_constraint: Test {
    my $self = shift;
    throws_ok { $self->eut->set(3) } qr/constraint.*Bool/;
}

sub set_if_1st: Test {
    my $self = shift;
    $self->eut->set(1);
    $self->eut->set_if_1st(0);
    is $self->eut->get, 1;
}

sub set_twice: Test {
    my $self = shift;
    $self->eut->set(1);
    $self->eut->set(0);
    is $self->eut->get, 0;
}

sub set_expression: Test {
    my $self = shift;
    $self->eut->set_expression("!0 # and a comment");
    is $self->eut->get, 1;
}

sub set_expression_fail_constraint: Test {
    my $self = shift;
    $self->eut->set_expression("1 + 1");
    throws_ok { $self->eut->get } qr/constraint.*Bool/;
}

sub set_expression_if_1st: Test {
    my $self = shift;
    $self->eut->set_expression("0 + 1");
    $self->eut->set_expression_if_1st("0 + 0");
    is $self->eut->get, 1;
}

sub set_expression_twice: Test {
    my $self = shift;
    $self->eut->set_expression("!0");
    $self->eut->set_expression("0");
    is $self->eut->get, 0;
}

sub set_expression_twice_with_get: Test {
    my $self = shift;
    $self->eut->set_expression(1);
    $self->eut->get;
    $self->eut->set_expression(0);
    is $self->eut->get, 0;
}

sub set_expression_then_value_then_expression: Test(2) {
    my $self = shift;
    $self->eut->set_expression(1);
    $self->eut->set(0);
    is $self->eut->get, 0;
    $self->eut->set_expression(1);
    is $self->eut->get, 1;
}

sub set_expression_then_value_if_1st: Test {
    my $self = shift;
    $self->eut->set_expression(1);
    $self->eut->set_if_1st(0);
    is $self->eut->get, 1;
}

sub set_value_then_expression_if_1st: Test {
    my $self = shift;
    $self->eut->set(1);
    $self->eut->set_expression_if_1st(0);
    is $self->eut->get, 1;
}

our $Memoization_Counter;
sub set_memoized: Test(3) {
    my $eut = Property->new(name => 'Size', isa => 'Num', is_memoized => 1, section => 'Qux');
    local $Memoization_Counter = 0;
    $eut->set_expression('++$'. __PACKAGE__. '::Memoization_Counter');
    $eut->get;
    is $Memoization_Counter, 1;
    $eut->get;
    is $Memoization_Counter, 1;
    is $eut->get, 1;
}

sub set_no_memoized: Test(2) {
    my $eut = Property->new(name => 'Size', isa => 'Num', section => 'Qux');
    local $Memoization_Counter = 0;
    $eut->set_expression('++$'. __PACKAGE__. '::Memoization_Counter');
    $eut->get;
    is $Memoization_Counter, 1;
    $eut->get;
    is $Memoization_Counter, 2;
}

sub clone_simple: Test {
    my $eut = Property->new(name => 'Foo', isa => 'Str', is_memoized => 1, section => 'Qux');
    $eut->set('foo');
    my $clone = $eut->clone;
    is $clone->get, 'foo';
}

sub clone_with_expression: Test {
    my $eut = Property->new(name => 'Foo', isa => 'Str', section => 'Qux');
    $eut->set_expression(' "!" x 3 ');
    $eut->get('Foo'); # just to ake sure it does'nt wreck anything
    my $clone = $eut->clone;
    is $clone->get, '!!!';
}

sub clone_never_been_set: Test {
    my $eut = Property->new(name => 'Foo', isa => 'Str', is_memoized => 1, section => 'Qux');
    my $clone = $eut->clone;
    throws_ok { $clone->get } qr/not been set yet/;
}

sub with_default: Test(2) {
    my $eut = Property->new(name => 'Foo', isa => 'Str', default => 'foo', section => 'Qux');
    is $eut->get, 'foo', 'starts with default';
    $eut->set('bar');
    is $eut->get, 'bar', 'but can still be set';
}

1;

